﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading;
using IPC.Communication.Framework.BasicFramework;
using IPC.Communication.Framework.Core.Net;

namespace IPC.Communication.Framework.Profinet.Melsec
{
    public class MelsecA3CServer : MelsecMcServer
    {
        private SerialPort serialPort;
        private bool _sumCheck = true;
        private int _format = 1;

        public byte Station
        {
            get;
            set;
        }

        public bool SumCheck
        {
            get { return _sumCheck; }
            set { _sumCheck = value; }
        }


        public int Format
        {
            get { return _format; }
            set { _format = value; }
        }


        public MelsecA3CServer()
            : base(isBinary: false)
        {
            serialPort = new SerialPort();
        }

        //protected override void ThreadPoolLoginAfterClientCheck(Socket socket, IPEndPoint endPoint)
        //{
        //    AppSession appSession = new AppSession();
        //    appSession.IpEndPoint = endPoint;
        //    appSession.WorkSocket = socket;
        //    try
        //    {
        //        socket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, SocketAsyncCallBack, appSession);
        //        AddClient(appSession);
        //    }
        //    catch
        //    {
        //        socket.Close();
        //        base.LogNet?.WriteDebug(ToString(), string.Format(StringResources.Language.ClientOfflineInfo, endPoint));
        //    }
        //}

        //[AsyncStateMachine(typeof(<SocketAsyncCallBack>d__14))]
        //[DebuggerStepThrough]
        //private void SocketAsyncCallBack(IAsyncResult ar)
        //{
        //    <SocketAsyncCallBack>d__14 stateMachine = new <SocketAsyncCallBack>d__14();
        //    stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.ar = ar;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //}

        private void SetSumCheck(byte[] command, int startLength, int endLength)
        {
            int num = 0;
            for (int i = startLength; i < command.Length - endLength; i++)
            {
                num += command[i];
            }
            byte[] array = SoftBasic.BuildAsciiBytesFrom((byte)num);
            command[command.Length - endLength] = array[0];
            command[command.Length - endLength + 1] = array[1];
        }

        private bool CalculatSumCheck(byte[] command, int startLength, int endLength)
        {
            int num = 0;
            for (int i = startLength; i < command.Length - endLength; i++)
            {
                num += command[i];
            }
            byte[] array = SoftBasic.BuildAsciiBytesFrom((byte)num);
            if (command[command.Length - endLength] != array[0] || command[command.Length - endLength + 1] != array[1])
            {
                return false;
            }
            return true;
        }

        private OperateResult<byte[]> ExtraMcCore(byte[] command)
        {
            byte b = byte.Parse(Encoding.ASCII.GetString(command, (Format == 2) ? 5 : 3, 2));
            if (Station != b)
            {
                return new OperateResult<byte[]>(String.Format("Station Not Match, need: {0}  but: {1}", Station, b));
            }
            if (Format == 1)
            {
                if (command[0] != 5)
                {
                    return new OperateResult<byte[]>("First Byte Must Start with 0x05");
                }
                if (SumCheck)
                {
                    if (!CalculatSumCheck(command, 1, 2))
                    {
                        return new OperateResult<byte[]>("Sum Check Failed!");
                    }
                    return OperateResult.CreateSuccessResult(command.SelectMiddle(11, command.Length - 13));
                }
                return OperateResult.CreateSuccessResult(command.SelectMiddle(11, command.Length - 11));
            }
            if (Format == 2)
            {
                if (command[0] != 5)
                {
                    return new OperateResult<byte[]>("First Byte Must Start with 0x05");
                }
                if (SumCheck)
                {
                    if (!CalculatSumCheck(command, 1, 2))
                    {
                        return new OperateResult<byte[]>("Sum Check Failed!");
                    }
                    return OperateResult.CreateSuccessResult(command.SelectMiddle(13, command.Length - 15));
                }
                return OperateResult.CreateSuccessResult(command.SelectMiddle(13, command.Length - 13));
            }
            if (Format == 3)
            {
                if (command[0] != 2)
                {
                    return new OperateResult<byte[]>("First Byte Must Start with 0x02");
                }
                if (SumCheck)
                {
                    if (command[command.Length - 3] != 3)
                    {
                        return new OperateResult<byte[]>("The last three Byte Must be 0x03");
                    }
                    if (!CalculatSumCheck(command, 1, 2))
                    {
                        return new OperateResult<byte[]>("Sum Check Failed!");
                    }
                    return OperateResult.CreateSuccessResult(command.SelectMiddle(11, command.Length - 14));
                }
                if (command[command.Length - 1] != 3)
                {
                    return new OperateResult<byte[]>("The last Byte Must be 0x03");
                }
                return OperateResult.CreateSuccessResult(command.SelectMiddle(11, command.Length - 12));
            }
            if (Format == 4)
            {
                if (command[0] != 5)
                {
                    return new OperateResult<byte[]>("First Byte Must Start with 0x05");
                }
                if (command[command.Length - 1] != 10)
                {
                    return new OperateResult<byte[]>("The last Byte must be 0x0D,0x0A");
                }
                if (command[command.Length - 2] != 13)
                {
                    return new OperateResult<byte[]>("The last Byte must be 0x0D,0x0A");
                }
                if (SumCheck)
                {
                    if (!CalculatSumCheck(command, 1, 4))
                    {
                        return new OperateResult<byte[]>("Sum Check Failed!");
                    }
                    return OperateResult.CreateSuccessResult(command.SelectMiddle(11, command.Length - 15));
                }
                return OperateResult.CreateSuccessResult(command.SelectMiddle(11, command.Length - 13));
            }
            return new OperateResult<byte[]>("Not Support Format:" + Format.ToString());
        }

        protected override byte[] PackCommand(ushort status, byte[] data)
        {
            if (data == null)
            {
                data = new byte[0];
            }
            if (data.Length == 0)
            {
                if (Format == 1)
                {
                    if (status == 0)
                    {
                        byte[] bytes = Encoding.ASCII.GetBytes("\u0006F90000FF00");
                        SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(bytes, 3);
                        return bytes;
                    }
                    byte[] bytes2 = Encoding.ASCII.GetBytes("\u0015F90000FF000000");
                    SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(bytes2, 3);
                    SoftBasic.BuildAsciiBytesFrom(status).CopyTo(bytes2, bytes2.Length - 4);
                    return bytes2;
                }
                if (Format == 2)
                {
                    if (status == 0)
                    {
                        byte[] bytes3 = Encoding.ASCII.GetBytes("\u000600F90000FF00");
                        SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(bytes3, 5);
                        return bytes3;
                    }
                    byte[] bytes4 = Encoding.ASCII.GetBytes("\u001500F90000FF000000");
                    SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(bytes4, 5);
                    SoftBasic.BuildAsciiBytesFrom(status).CopyTo(bytes4, bytes4.Length - 4);
                    return bytes4;
                }
                if (Format == 3)
                {
                    if (status == 0)
                    {
                        byte[] bytes5 = Encoding.ASCII.GetBytes("\u0002F90000FF00QACK\u0003");
                        SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(bytes5, 3);
                        return bytes5;
                    }
                    byte[] bytes6 = Encoding.ASCII.GetBytes("\u0002F90000FF00QNAK0000\u0003");
                    SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(bytes6, 3);
                    SoftBasic.BuildAsciiBytesFrom(status).CopyTo(bytes6, bytes6.Length - 5);
                    return bytes6;
                }
                if (Format == 4)
                {
                    if (status == 0)
                    {
                        byte[] bytes7 = Encoding.ASCII.GetBytes("\u0002F90000FF00");
                        SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(bytes7, 3);
                        return bytes7;
                    }
                    byte[] bytes8 = Encoding.ASCII.GetBytes("\u0015F90000FF000000\r\n");
                    SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(bytes8, 3);
                    SoftBasic.BuildAsciiBytesFrom(status).CopyTo(bytes8, bytes8.Length - 6);
                    return bytes8;
                }
                return null;
            }
            if (Format == 1)
            {
                if (status != 0)
                {
                    byte[] bytes9 = Encoding.ASCII.GetBytes("\u0015F90000FF000000");
                    SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(bytes9, 3);
                    SoftBasic.BuildAsciiBytesFrom(status).CopyTo(bytes9, bytes9.Length - 4);
                    return bytes9;
                }
                byte[] array = new byte[(SumCheck ? 14 : 12) + data.Length];
                Encoding.ASCII.GetBytes("\u0002F90000FF00").CopyTo(array, 0);
                SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(array, 3);
                data.CopyTo(array, 11);
                array[array.Length - ((!SumCheck) ? 1 : 3)] = 3;
                if (SumCheck)
                {
                    SetSumCheck(array, 1, 2);
                }
                return array;
            }
            if (Format == 2)
            {
                if (status != 0)
                {
                    byte[] bytes10 = Encoding.ASCII.GetBytes("\u001500F90000FF000000");
                    SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(bytes10, 5);
                    SoftBasic.BuildAsciiBytesFrom(status).CopyTo(bytes10, bytes10.Length - 4);
                    return bytes10;
                }
                byte[] array2 = new byte[(SumCheck ? 16 : 14) + data.Length];
                Encoding.ASCII.GetBytes("\u000200F90000FF00").CopyTo(array2, 0);
                SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(array2, 5);
                data.CopyTo(array2, 13);
                array2[array2.Length - ((!SumCheck) ? 1 : 3)] = 3;
                if (SumCheck)
                {
                    SetSumCheck(array2, 1, 2);
                }
                return array2;
            }
            if (Format == 3)
            {
                if (status != 0)
                {
                    byte[] bytes11 = Encoding.ASCII.GetBytes("\u0002F90000FF00QNAK0000\u0003");
                    SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(bytes11, 3);
                    SoftBasic.BuildAsciiBytesFrom(status).CopyTo(bytes11, bytes11.Length - 5);
                    return bytes11;
                }
                byte[] array3 = new byte[(SumCheck ? 18 : 16) + data.Length];
                Encoding.ASCII.GetBytes("\u0002F90000FF00QACK").CopyTo(array3, 0);
                SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(array3, 3);
                array3[array3.Length - ((!SumCheck) ? 1 : 3)] = 3;
                data.CopyTo(array3, 15);
                if (SumCheck)
                {
                    SetSumCheck(array3, 1, 2);
                }
                return array3;
            }
            if (Format == 4)
            {
                if (status != 0)
                {
                    byte[] bytes12 = Encoding.ASCII.GetBytes("\u0015F90000FF000000\r\n");
                    SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(bytes12, 3);
                    SoftBasic.BuildAsciiBytesFrom(status).CopyTo(bytes12, bytes12.Length - 6);
                    return bytes12;
                }
                byte[] array4 = new byte[(SumCheck ? 16 : 14) + data.Length];
                Encoding.ASCII.GetBytes("\u0002F90000FF00").CopyTo(array4, 0);
                SoftBasic.BuildAsciiBytesFrom(Station).CopyTo(array4, 3);
                array4[array4.Length - (SumCheck ? 5 : 3)] = 3;
                data.CopyTo(array4, 11);
                if (SumCheck)
                {
                    SetSumCheck(array4, 1, 4);
                }
                array4[array4.Length - 2] = 13;
                array4[array4.Length - 1] = 10;
                return array4;
            }
            return null;
        }

        public void StartSerial(string com)
        {
            StartSerial(com, 9600);
        }

        public void StartSerial(string com, int baudRate)
        {
            StartSerial(delegate(SerialPort sp)
            {
                sp.PortName = com;
                sp.BaudRate = baudRate;
                sp.DataBits = 8;
                sp.Parity = Parity.None;
                sp.StopBits = StopBits.One;
            });
        }

        public void StartSerial(Action<SerialPort> inni)
        {
            if (!serialPort.IsOpen)
            {
                if (inni != null)
                {
                    inni.Invoke(serialPort);
                }
                serialPort.ReadBufferSize = 1024;
                serialPort.ReceivedBytesThreshold = 1;
                serialPort.Open();
                serialPort.DataReceived += SerialPort_DataReceived;
            }
        }

        public void CloseSerial()
        {
            if (serialPort.IsOpen)
            {
                serialPort.Close();
            }
        }

        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int num = 0;
            byte[] array = new byte[1024];
            int num2;
            do
            {
                Thread.Sleep(20);
                num2 = serialPort.Read(array, num, serialPort.BytesToRead);
                num += num2;
            }
            while (num2 != 0);
            if (num == 0)
            {
                return;
            }
            byte[] array2 = array.SelectBegin(num);
            if (array2.Length < 3)
            {
                if (base.LogNet != null)
                {
                    base.LogNet.WriteError(ToString(), "[" + serialPort.PortName + "] Uknown Data：" + array2.ToHexString(' '));
                }
                return;
            }
            OperateResult<byte[]> operateResult = ExtraMcCore(array2);
            if (!operateResult.IsSuccess)
            {
                if (base.LogNet != null)
                {
                    base.LogNet.WriteDebug(ToString(), "[" + serialPort.PortName + "] " + operateResult.Message + " : " + SoftBasic.GetAsciiStringRender(array2));
                }
            }
            else
            {
                byte[] array3 = ReadFromMcAsciiCore(operateResult.Content);
                if (base.LogNet != null)
                {
                    base.LogNet.WriteDebug(ToString(), "[" + serialPort.PortName + "] " + StringResources.Language.Receive + "：" + SoftBasic.GetAsciiStringRender(array2));
                }
                if (array3 != null)
                {
                    serialPort.Write(array3, 0, array3.Length);
                    if (base.LogNet != null)
                    {
                        base.LogNet.WriteDebug(ToString(), "[" + serialPort.PortName + "] " + StringResources.Language.Send + "：" + SoftBasic.GetAsciiStringRender(array3));
                    }
                }
            }
            if (base.IsStarted)
            {
                RaiseDataReceived(sender, array2);
            }
        }
    }
}
